package main

import "fmt"

//结构体是值类型

type person struct {
	name, gender string
}

func f(x person) {
	x.gender = "女"
	fmt.Printf("值传递函数中x===%T \n", x) //修改的是副本的gender
	fmt.Println(x)
}

//go语言中函数传参，永远是拷贝
func main() {
	var p person
	p.name = "周林"
	p.gender = "男"
	f(p) //值传递
	fmt.Printf("值传递后p===%T \n", p)
	fmt.Println(p)
	fmt.Printf("引用传递前&p===%T \n", &p)
	fmt.Printf("引用传递前&p===%v \n", &p)
	f2(&p)
	fmt.Printf("引用传递后&p===%T \n", &p)
	fmt.Printf("引用传递后&p===%v \n", &p)
	fmt.Printf("引用传递后p===%T \n", p)
	fmt.Println(p)

	//2.声明变量，并初始化,p3中保存的都是值，不是引用的内存地址
	//2.1key-value初始化
	var p13 = person{
		name:   "元帅",
		gender: "男",
	}
	fmt.Printf("p13===%T----%#v \n", p13, p13)

	//2.2使用值列表的形式初始化，值得顺序要和结构体定义时字段的顺序一致
	p14 := person{
		"小王子",
		"男",
	}
	fmt.Printf("p14===%T----%#v \n", p14, p14)

	//下面是指针类型结构体，都是引用类型
	//1.结构体指针，获得都是引用传递的内存地址
	var p2 = new(person)
	fmt.Printf("指针类型p2===%T \n", p2)
	fmt.Printf("%x \n", p2)
	fmt.Printf("%v \n", p2)
	fmt.Printf("%p \n", &p2)
	p2.name = "赵金鼎"
	p2.gender = "男"
	//(*p2).name = "zhaojinding" //语法糖
	fmt.Printf("%x \n", p2)  //十六进制的内存地址
	fmt.Printf("%p \n", p2)  //p2保存的值就是一个内存地址
	fmt.Printf("%p \n", &p2) //p2的内存地址
	fmt.Printf("%v \n", p2)

	//2.声明变量，并初始化
	//2.1key-value初始化
	var p3 = &person{
		name:   "元帅",
		gender: "男",
	}
	fmt.Printf("p3===%T----%#v \n", p3, p3)

	//2.2使用值列表的形式初始化，值得顺序要和结构体定义时字段的顺序一致
	p4 := &person{
		"小王子",
		"男",
	}
	fmt.Printf("p4===%T----%#v \n", p4, p4)
	fmt.Printf("p4===%T----%#v \n", p4.name, p4.name)
	fmt.Printf("p4===%p \n", &(p4.name)) //语法糖

	f3(p4) //p4本身就是指针类型，是一个指针内存地址
	fmt.Printf("指针类型p4，引用传递后p4===%T----%#v \n", p4, p4)

}

//引用传递
func f2(x *person) {
	x.gender = "女"   //根据内存地址找到那个原变量，修改的就是愿挨的变量
	(*x).name = "王五" //语法糖  自动根据指针找到对应的变量
}

func f3(x *person) {
	x.gender = "男"   //根据内存地址找到那个原变量，修改的就是愿挨的变量
	(*x).name = "张三" //语法糖  自动根据指针找到对应的变量
}
